//
// Created by admin on 2022/8/30.
//

#ifndef LEETCODE_TYPE_TRAIT_HPP
#define LEETCODE_TYPE_TRAIT_HPP

#include <cstring>
#include "macros_deal.hpp"
#include "cxxabi.h"

namespace LOCATION_UTIL {
    using namespace std;

    class LogWrapper {
        std::string logInfo_;
        const char *file_;
        const char *func_{nullptr};
        unsigned int row_;
        const char *color_{nullptr};
        const char *type_{nullptr};


    public:
        LogWrapper(const char *file, const char *func, unsigned int row) : file_(file), func_(func), row_(row) {}

        LogWrapper(const char *file, unsigned int row) : file_(file), row_(row) {}

        inline string toString() const {
            stringstream ss;
            ss << file_ << ":" << row_;
            if (func_ != nullptr) {
                ss << "[" << func_ << "]";
            }
            return ss.str();
        };


        template<typename E, typename T>
        friend std::basic_ostream<E, T> &operator<<(std::basic_ostream<E, T> &os, const LogWrapper &wrapper) {
            return os << wrapper.toString();
        }
    };

#define LOCATION LOCATION_UTIL::LogWrapper(__FILE__, __PRETTY_FUNCTION__, __LINE__)
#define PF __PRETTY_FUNCTION__
#define FL __FILE__
#define LN __LINE__
#define FILE_LINE LOCATION_UTIL::LogWrapper(__FILE__,  __LINE__)
}


namespace TypeTrait {
    using namespace LOCATION_UTIL;
    static const char *nameHead = "TypeTrait::TypeWrapper<";
    static const size_t start = strlen(nameHead);
    static const size_t stripLen = start + 1;

    static const char CHAR_END = '\0';

    template<typename T>
    struct TypeWrapper {
    };

    /*获取实际类型名称*/
    template<typename T>
    static const char *fullTypeName() {
        int status = 0;
        std::size_t size = 0;
        auto fullTypeNameStr = abi::__cxa_demangle(typeid(TypeWrapper<T>).name(), nullptr, &size, &status);
        auto total_len = strlen(fullTypeNameStr);
        fullTypeNameStr[total_len - 1] = CHAR_END;
        return fullTypeNameStr + start;
    }


    template<typename ...T>
    static void printFullTypeName(const char *descp = "") {
        static_assert(sizeof...(T) > 0, "intro type nums must be bigger than ZERO!");
        std::cout << descp << " with type info: " << std::endl;
        std::initializer_list<int>{
                (std::cout << fullTypeName<T>() << std::endl, 0)...
        };
    }

    template<typename ...T>
    static void printFullTypeName(const LogWrapper &logWrapper) {
        static_assert(sizeof...(T) > 0, "intro type nums must be bigger than ZERO!");
        std::cout << "line of " << logWrapper << " with type info: " << std::endl;
        std::initializer_list<int>{
                (std::cout << fullTypeName<T>() << std::endl, 0)...
        };
    }


/*example: PrintFullTypeName(type1,type2)*/
#define PrintFullTypeName(...) TypeTrait::printFullTypeName<__VA_ARGS__>(FILE_LINE)

}
#endif //LEETCODE_TYPE_TRAIT_HPP
